package services

import java.awt.Color
import java.awt.Font
import java.awt.Graphics
import java.awt.Graphics2D
import java.awt.image.BufferedImage
import java.io.{File, FileOutputStream}
import java.util.Random

/**
 * 验证码生成器
 *
 * @author 诺坎普10号
 * @date 2020-2-25
 */

/**
 *
 */
class CpachaUtil() {
  /**
   * 验证码来源
   */
  final private val code = Array('2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z')
  /**
   * 字体
   */
  final private val fontNames = Array[String]("黑体", "宋体", "Courier", "Arial", "Verdana", "Times", "Tahoma", "Georgia")
  /**
   * 字体样式
   */
  final private val fontStyles = Array[Int](Font.BOLD, Font.ITALIC | Font.BOLD)
  /**
   * 验证码长度
   * 默认4个字符
   */
  private var vcodeLen = 4
  /**
   * 验证码图片字体大小
   * 默认17
   */
  private var fontsize = 21
  /**
   * 验证码图片宽度
   */
  private var width = (fontsize + 1) * vcodeLen + 10
  /**
   * 验证码图片高度
   */
  private var height = fontsize + 12
  /**
   * 干扰线条数
   * 默认3条
   */
  private var disturbline = 3

  /**
   * 指定验证码长度
   *
   * @param vcodeLen 验证码长度
   */
  def this(vcodeLen: Int) = {
    this()
    this.vcodeLen = vcodeLen
    this.width = (fontsize + 1) * vcodeLen + 10
  }

  /**
   * 指定验证码长度、图片宽度、高度
   *
   * @param vcodeLen
   * @param width
   * @param height
   */
  def this(vcodeLen: Int, width: Int, height: Int) = {
    this()
    this.vcodeLen = vcodeLen
    this.width = width
    this.height = height
  }

  /**
   * 生成验证码图片
   *
   * @param vcode    要画的验证码
   * @param drawline 是否画干扰线
   * @return
   */
  def generatorVCodeImage(vcode: String, drawline: Boolean): BufferedImage = { //创建验证码图片
    val vcodeImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
    val g = vcodeImage.getGraphics
    //填充背景色
    g.setColor(new Color(246, 240, 250))
    g.fillRect(0, 0, width, height)
    if (drawline) drawDisturbLine(g)
    //用于生成伪随机数
    val ran = new Random()
    //在图片上画验证码
    for (i <- 0 until vcode.length) { //设置字体
      g.setFont(new Font(fontNames(ran.nextInt(fontNames.length)), fontStyles(ran.nextInt(fontStyles.length)), fontsize))
      //随机生成颜色
      g.setColor(getRandomColor)
      //画验证码
      g.drawString( vcode.charAt(i).toString, i * fontsize + 10, fontsize + 5)
    }
    //释放此图形的上下文以及它使用的所有系统资源
    g.dispose()
    vcodeImage
  }

  /**
   * 获得旋转字体的验证码图片
   *
   * @param vcode
   * @param drawline 是否画干扰线
   * @return
   */
  def generatorRotateVCodeImage(vcode: String, drawline: Boolean): BufferedImage = {
    val rotateVcodeImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
    val g2d = rotateVcodeImage.createGraphics
    g2d.setColor(new Color(246, 240, 250))
    g2d.fillRect(0, 0, width, height)
    if (drawline) drawDisturbLine(g2d)
    for (i <- 0 until vcode.length) {
      val rotateImage = getRotateImage(vcode.charAt(i))
      g2d.drawImage(rotateImage, null, (this.height * 0.7).toInt * i, 0)
    }
    g2d.dispose()
    rotateVcodeImage
  }

  /**
   * 生成验证码
   *
   * @return 验证码
   */
  def generatorVCode: String = {
    val len = code.length
    val ran = new Random()
    val sb = new StringBuffer
    for (i <- 0 until vcodeLen) {
      val index = ran.nextInt(len)
      sb.append(code(index))
    }
    sb.toString
  }

  /**
   * 为验证码图片画一些干扰线
   *
   * @param g
   */
  private def drawDisturbLine(g: Graphics): Unit = {
    val ran = new Random()
    for (i <- 0 until disturbline) {
      val x1 = ran.nextInt(width)
      val y1 = ran.nextInt(height)
      val x2 = ran.nextInt(width)
      val y2 = ran.nextInt(height)
      g.setColor(getRandomColor)
      //画干扰线
      g.drawLine(x1, y1, x2, y2)
    }
  }

  /**
   * 获取一张旋转的图片
   *
   * @param c 要画的字符
   * @return
   */
  private def getRotateImage(c: Char) = {
    val rotateImage = new BufferedImage(height, height, BufferedImage.TYPE_INT_ARGB)
    val g2d = rotateImage.createGraphics
    //设置透明度为0
    g2d.setColor(new Color(255, 255, 255, 0))
    g2d.fillRect(0, 0, height, height)
    val ran = new Random()
    g2d.setFont(new Font(fontNames(ran.nextInt(fontNames.length)), fontStyles(ran.nextInt(fontStyles.length)), fontsize))
    g2d.setColor(getRandomColor)
    val theta = getTheta
    //旋转图片
    g2d.rotate(theta, height / 2, height / 2)
    g2d.drawString(Character.toString(c), (height - fontsize) / 2, fontsize + 5)
    g2d.dispose()
    rotateImage
  }

  /**
   * @return 返回一个随机颜色
   */
  private def getRandomColor = {
    val ran = new Random()
    new Color(ran.nextInt(220), ran.nextInt(220), ran.nextInt(220))
  }

  /**
   * @return 角度
   */
  private def getTheta = (if ((Math.random * 1000).toInt % 2 == 0) -1
  else 1) * Math.random

  /**
   * @return 验证码字符个数
   */
  def getVcodeLen: Int = vcodeLen

  /**
   * 设置验证码字符个数
   *
   * @param vcodeLen
   */
  def setVcodeLen(vcodeLen: Int): Unit = {
    this.width = (fontsize + 3) * vcodeLen + 10
    this.vcodeLen = vcodeLen
  }

  /**
   * @return 字体大小
   */
  def getFontsize: Int = fontsize

  /**
   * 设置字体大小
   *
   * @param fontsize
   */
  def setFontsize(fontsize: Int): Unit = {
    this.width = (fontsize + 3) * vcodeLen + 10
    this.height = fontsize + 15
    this.fontsize = fontsize
  }

  /**
   * @return 图片宽度
   */
  def getWidth: Int = width

  /**
   * 设置图片宽度
   *
   * @param width
   */
  def setWidth(width: Int): Unit = {
    this.width = width
  }

  /**
   * @return 图片高度
   */
  def getHeight: Int = height

  /**
   * 设置图片高度
   *
   * @param height
   */
  def setHeight(height: Int): Unit = {
    this.height = height
  }

  /**
   * @return 干扰线条数
   */
  def getDisturbline: Int = disturbline

  /**
   * 设置干扰线条数
   *
   * @param disturbline
   */
  def setDisturbline(disturbline: Int): Unit = {
    this.disturbline = disturbline
  }
}

object CpachaUtil {

  def get(vcodeLen: Int = 4, width: Int = 100, height: Int = 30, cpachaType: String = "loginCpacha") = {
    import javax.imageio.ImageIO
    import java.awt.image.BufferedImage
    import java.io.IOException
    //根据页面传入的验证码长度、图片宽度以及图片长度来实例化验证码实体//根据页面传入的验证码长度、图片宽度以及图片长度来实例化验证码实体

    val cpachaUtil = new CpachaUtil(vcodeLen, width, height)
    //生成验证码
    val generatorVCode = cpachaUtil.generatorVCode
    //把验证码存入session
    println(cpachaType, generatorVCode)
    //根据验证码生成相应的验证码图片
    val generatorRotateVCodeImage = cpachaUtil.generatorRotateVCodeImage(generatorVCode, true)
    //    var getOutputStream = new FileOutputStream(new File("test.gif" ))
    //    ImageIO.write(generatorRotateVCodeImage, "gif",getOutputStream)
    //    getOutputStream
    (generatorRotateVCodeImage, generatorVCode)
  }

}
